package ymy;

import ymy.common.*;
import java.util.*;

/**
特殊仿真场景的仿真过程：仿真的主要目的是模拟十字路口的车辆通行与通信过程。
车辆分为两种，分别是停驻车辆和移动车辆。
对于停驻车辆，我们将其分布在十字路口的道路两边；对于移动车辆，我们设置所有车辆均通过十字路口并选择合适的方向前进。
具体示意图如下：
                |      |
                |      |
                |      |
                | |  | |
                | |  | |
                | v  v |
----------------|      |------------------
        ---->               <----
        ---->               <----
----------------|      |------------------
                | ^  ^ |
                | |  | |
                | |  | |
                |      |
                |      |
因此，
对于停驻车辆，我们选取[505-520]+[331-346]+[1043-1059]+[869-884]+[2561-2576]+[2795-2810]+[1843-1858]+[2077-2092]
对于移动车辆，我们选取[148-178(e)]+[748-778(e)]+[359-389(o)]+[1019-1138(o)]
*/
public class SpecificSimulator extends BaseSimulator {

    public static double[] speedArray = new double[GeneralConfig.SPEED_CAPACITY];
    public static List<Integer> mvSet = new ArrayList<>();
    public static List<Integer> pkSet = new ArrayList<>();

    public SpecificSimulator(Environment env) {
        super(env);
        this.internalInit();
    }

    public void internalInit() {
        Random random = new Random(System.currentTimeMillis());
        int speed_ten_times_range = (int)((GeneralConfig.VEHICLE_UPPER_SPEED - GeneralConfig.VEHICLE_LOWER_SPEED) * 10.0);
        for (int i = 0; i < GeneralConfig.SPEED_CAPACITY; i++) {
            double speed = random.nextInt(speed_ten_times_range) / 10.0 + GeneralConfig.VEHICLE_LOWER_SPEED;
            speedArray[i] = speed;
        }

        int pkcnt = SpecificConfig.PARK_VEHICLES;
        this.pkSet.clear();
        for (int i = 0; i < pkcnt; i++) {
            this.pkSet.add(SpecificConfig.PARK_VEHICLES_IDS[i]);
        }

        int mvcnt = SpecificConfig.MOVE_VEHICLES;
        this.mvSet.clear();
        for (int j = 0; j < mvcnt; j++) {
            this.mvSet.add(SpecificConfig.MOVE_VEHICLES_IDS[j]);
        }
    }

    @Override
    public void vehicleMoveAction(Vehicle v, double duration) {
        double min_x = GeneralConfig.ROAD_WIDTH / 2;
        double max_x = GeneralConfig.ROAD_WIDTH / 2 + GeneralConfig.ROAD_HLEN * 2;
        double min_y = GeneralConfig.ROAD_WIDTH / 2;
        double max_y = GeneralConfig.ROAD_WIDTH / 2 + GeneralConfig.ROAD_VLEN * 2;

        int direct = v.getDirection();
        Coordinate coor = v.getPosition();
        double x = coor.getX();
        double y = coor.getY();
        double len = v.getSpeed() * duration;

        if (direct == GeneralConfig.WEST) {
            x = x - len;
            x = Math.max(x, min_x);
        }
        if (direct == GeneralConfig.EAST) {
            x = x + len;
            x = Math.min(x, max_x);
        }
        if (direct == GeneralConfig.SOUTH) {
            y = y - len;
            y = Math.max(y, min_y);
        }
        if (direct == GeneralConfig.NORTH) {
            y = y + len;
            y = Math.min(y, max_y);
        }

        coor.setX(x);
        coor.setY(y);
        v.setPosition(coor);
        v.setDirection(direct);

        if (GeneralConfig.DEBUG_UPDATE) {
            System.out.println("Vehicle ID: " + v.getId());
            System.out.println("Vehicle Coordinate: " + coor);
            System.out.println("------------------------------------");
        }
    }

    @Override
    public void initParkVehicles() {
        if (GeneralConfig.DEBUG_INFO) {
            System.out.println("[INFO]确定初始化停放车辆信息...");
        }
        int count = 0;
        for (Integer val : this.pkSet) {
            // 获取停放车辆的停车点信息
            Environment.ParkLocation pl = this.environment.getSpecificParkLocation(val);

            Vehicle pv = new Vehicle();
            pv.setId(this.vid++);
            pv.setParked(true);
            pv.setRunning(true);
            pv.setPosition(Utility.copyOfCoordinate(pl.getCoordinate()));
            pv.setDirection(GeneralConfig.UNKNOWN);
            pv.setArea(pl.getArea());

            pv.setDelay(GeneralConfig.VEHICLE_PARK_PTIME);
            pv.setGain(1.0);
            pv.setSpeed(0);
            pv.setMoment(0);
            pv.setDistance(0);

            if (GeneralConfig.DEBUG_INIT) {
                System.out.println("[INFO]第" + (count + 1) + "辆停驻车辆信息：");
                System.out.println(pv);
            }
            count++;
            this.parkVehicleMap.put(pv.getId(), pv);
        }
        if (GeneralConfig.DEBUG_INIT)
            System.out.println("[INFO]成功添加" + this.parkVehicleMap.size() + "辆停驻车辆！！");
    }

    @Override
    public void initMoveVehicles() {
        if (GeneralConfig.DEBUG_INFO)
            System.out.println("[INFO]确定初始化移动车辆信息...");

        int count = 0;
        for (Integer val : this.mvSet) {
            // 获取移动车辆发车点信息
            Environment.MoveLocation wl = this.environment.getSpecificMoveLocation(val);

            // 随机得到移动车辆的发车时刻
            double time = 0;
            //time = (double)random.nextInt((int) SpecificConfig.SIMU_DURATION / 10);

            Vehicle wv = new Vehicle();
            wv.setId(this.vid++);
            wv.setParked(false);
            wv.setRunning(false);
            wv.setPosition(Utility.copyOfCoordinate(wl.getCoordinate()));
            wv.setDirection(wl.getDirection());
            wv.setArea(null);

            wv.setSpeed(speedArray[count]);
            wv.setDelay(GeneralConfig.VEHICLE_MOVE_PTIME);
            wv.setGain(GeneralConfig.VEHICLE_GAIN);
            wv.setMoment(time);
            wv.setDistance(0);

            if (GeneralConfig.DEBUG_INIT) {
                System.out.println("[INFO]第" + (count + 1) + "辆移动车辆信息：");
                System.out.println(wv);
            }
            count++;
            this.moveVehicleMap.put(wv.getId(), wv);
        }
        if (GeneralConfig.DEBUG_INIT)
            System.out.println("[INFO]成功添加" + this.moveVehicleMap.size() + "辆移动车辆！！");
    }

    @Override
    public void initParkVehiclesOV() {
        if (GeneralConfig.DEBUG_INFO) {
            System.out.println("[INFO]确定初始化停放车辆信息...");
        }
        int[][] plmatrix = SpecificConfig.PARK_VEHICLES_OV;
        for (int i = 0, count = 0; i < plmatrix.length; i++) {
            int start = plmatrix[i][0];
            int end = plmatrix[i][1];
            for (int j = start; j < end; j++) {
                // 获取停放车辆的停车点信息
                Environment.ParkLocation pl = this.environment.getSpecificParkLocation(j);

                Vehicle pv = new Vehicle();
                pv.setId(this.vid++);
                pv.setParked(true);
                pv.setRunning(true);
                pv.setPosition(Utility.copyOfCoordinate(pl.getCoordinate()));
                pv.setDirection(GeneralConfig.UNKNOWN);
                pv.setArea(pl.getArea());

                pv.setDelay(GeneralConfig.VEHICLE_PARK_PTIME);
                pv.setGain(1.0);
                pv.setSpeed(0);
                pv.setMoment(0);
                pv.setDistance(0);

                if (GeneralConfig.DEBUG_INIT) {
                    System.out.println("[INFO]第" + (count + 1) + "辆停驻车辆信息：");
                    System.out.println(pv);
                }
                count++;
                this.parkVehicleMap.put(pv.getId(), pv);
            }
        }
        if (GeneralConfig.DEBUG_INIT)
            System.out.println("[INFO]成功添加" + this.parkVehicleMap.size() + "辆停驻车辆！！");
    }

    @Override
    public void initMoveVehiclesOV() {
        if (GeneralConfig.DEBUG_INFO)
            System.out.println("[INFO]确定初始化移动车辆信息...");
        int[][] wlmatrix = SpecificConfig.MOVE_VEHICLES_OV;
        int[] odevity = SpecificConfig.ODEVTIY;
        for (int i = 0, count = 0; i < wlmatrix.length; i++) {
            int start = wlmatrix[i][0];
            int end = wlmatrix[i][1];
            for (int j = start; j < end; j++) {
                if (j % 2 == odevity[i])
                    continue;

                // 获取移动车辆发车点信息
                Environment.MoveLocation wl = this.environment.getSpecificMoveLocation(j);

                // 随机得到移动车辆的发车时刻
                double time = 0;
                //time = (double)random.nextInt((int) SpecificConfig.SIMU_DURATION / 10);

                Vehicle wv = new Vehicle();
                wv.setId(this.vid++);
                wv.setParked(false);
                wv.setRunning(false);
                wv.setPosition(Utility.copyOfCoordinate(wl.getCoordinate()));
                wv.setDirection(wl.getDirection());
                wv.setArea(null);

                wv.setSpeed(speedArray[count]);
                wv.setDelay(GeneralConfig.VEHICLE_MOVE_PTIME);
                wv.setGain(GeneralConfig.VEHICLE_GAIN);
                wv.setMoment(time);
                wv.setDistance(0);

                if (GeneralConfig.DEBUG_INIT) {
                    System.out.println("[INFO]第" + (count + 1) + "辆移动车辆信息：");
                    System.out.println(wv);
                }
                count++;
                this.moveVehicleMap.put(wv.getId(), wv);
            }
        }
        if (GeneralConfig.DEBUG_INIT)
            System.out.println("[INFO]成功添加" + this.moveVehicleMap.size() + "辆移动车辆！！");
    }

    public StageResult specificSimulationProcess(boolean ov) {
        int helloCount = (int)(SpecificConfig.SAMPLE_PERIOD / SpecificConfig.HELLO_PERIOD);
        int sampleCount = (int)(SpecificConfig.PROCEED_PERIOD / SpecificConfig.SAMPLE_PERIOD);
        int processCount = (int)(SpecificConfig.SIMU_DURATION / SpecificConfig.PROCEED_PERIOD);

        return this.simulationProcess(SpecificConfig.SAMPLE_PERIOD, helloCount, sampleCount, processCount, ov);
    }
}
